package com.example.utils;


/**
 * AIS工具类
 *
 * @author: Fred
 * @email 453086@qq.com
 * @create: 2024-09-29 08:32
 */
public class AisUtils {

    private static final double METERS_PER_DEGREE_LATITUDE = 111120;
    private static final double[][] STANDARD_POINTS = {{29.19720150937384, 119.4596528222393}, {29.19686902671549, 119.45930413506738}, {29.19653186010177, 119.45896617673151}, {29.196180643700146, 119.45861748955956}, {29.195857523548142, 119.45826880238764}, {29.195562499911375, 119.45788256428949}, {29.19526279249058, 119.4574909617733}, {29.194958401244662, 119.45709935925719}, {29.194668057983463, 119.45672384999507}, {29.194321518176224, 119.45635906956906}, {29.193993709172588, 119.45603720448726}, {29.193586287950296, 119.45579044125788}, {29.193155449954318, 119.45559732220885}, {29.192766757600438, 119.45539883874173}, {29.192307817743725, 119.455264728291}, {29.191880799504418, 119.45518835699819}, {29.19145463745248, 119.4550971618917}, {29.191009741113334, 119.45500060236715}, {29.19055079339367, 119.45493086493279}, {29.190091843620223, 119.45486649191643}, {29.189623525407825, 119.45478602564604}, {29.189211403611964, 119.45473774588379}, {29.188775864005194, 119.45468946612154}, {29.188349689051293, 119.45460363543305}, {29.187890729428304, 119.45455535567085}, {29.18744113433702, 119.45450171149056}, {29.18697748733507, 119.45446416056436}, {29.186561452130164, 119.4544319740562}, {29.186107167859106, 119.45440515196606}, {29.185648198201932, 119.45435687220379}, {29.18516112611563, 119.4543032280235}, {29.1847115190602, 119.4542442194251}, {29.184303932045154, 119.45420020166456}, {29.183854321232758, 119.45417337957443}, {29.183409391926475, 119.45413582864822}, {29.18297382768381, 119.45410900655804}, {29.18251032328142, 119.45405138567884}, {29.182060704608247, 119.4540138347526}, {29.181602724701392, 119.4539601905723}, {29.181162469209312, 119.4539226396461}, {29.18071752822877, 119.45388508871989}, {29.18025385083797, 119.45383680895763}, {29.179822956838777, 119.45380462244945}, {29.179347353357315, 119.45374561385111}, {29.178916455551203, 119.4536919696708}, {29.17845745372385, 119.45361686781838}, {29.17799844984323, 119.45351494387587}, {29.17762375127566, 119.45338619784314}, {29.177174111188464, 119.45322526530228}, {29.176771306937283, 119.45303751067122}, {29.176345082112547, 119.45288730696639}, {29.175928223154003, 119.45272101000748}, {29.1754411049221, 119.4525225265403}, {29.175052345443376, 119.45235086516344}, {29.174638363619394, 119.45218456820452}, {29.17420744603922, 119.45196462706531}, {29.1738225591601, 119.451763813064}, {29.173429109618098, 119.45154923634291}, {29.17303097461756, 119.4513132019496}, {29.172632838072587, 119.45107180313829}, {29.172239383969654, 119.45083040432696}, {29.171836560349263, 119.45059973435168}, {29.171438419170954, 119.45034224228628}, {29.171063696651146, 119.45006865696675}, {29.170688972763287, 119.4497360630489}, {29.170356404166952, 119.44945174889341}, {29.169948889065708, 119.44907623963132}, {29.169658475017698, 119.44875973896754}, {29.169358691912777, 119.44840568737756}, {29.16905890793231, 119.44800872044338}, {29.16878254379975, 119.4476171179272}, {29.168510863079774, 119.4471826000668}, {29.168290707486165, 119.44678026871455}, {29.16807523559693, 119.44626528458372}, {29.167887868369064, 119.44582003788724}, {29.167719237571617, 119.44530505375634}, {29.16762086947851, 119.44485980705987}, {29.167485027671148, 119.44435555176506}, {29.16744286983233, 119.44385666088827}, {29.167391343561334, 119.44333631233944}, {29.167358554102705, 119.44282132820861}, {29.167311712000767, 119.44232780174984}, {29.167307027789406, 119.44182354645505}, {29.16732108042285, 119.4412602825619}, {29.167330448844126, 119.44069701866877}, {29.167363238311708, 119.44022494988215}, {29.16740539618327, 119.43975288109552}, {29.167453027118796, 119.43923513049077}, {29.167504553358796, 119.43872014635991}, {29.16758418476978, 119.43818906897496}, {29.167621658353568, 119.43770090693425}, {29.167649763532438, 119.43715373629524}, {29.16769660548009, 119.43670312518074}, {29.167766868361568, 119.43616379484497}, {29.16780434187865, 119.43563808187805}, {29.167865236314768, 119.43510700449312}, {29.16793549908077, 119.43462957128848}, {29.167987025078617, 119.43415750250183}, {29.1680619719384, 119.4336049674447}, {29.16811818204731, 119.4330792544779}, {29.168174392125493, 119.43256963476506}, {29.16820249715302, 119.43206001505224}, {29.168254023016843, 119.43157185301152}, {29.168318443012566, 119.43104927078474}, {29.16836528465514, 119.43051282898178}, {29.16845428371707, 119.43006758228, 53}};

    /**
     * 根据当前坐标、航向和速度计算下一个点的经纬度。
     */
    public static double[] calculateNextPosition(double currentLatitude, double currentLongitude, double course, double speedInKnots) {
        // 确定是否反向遍历
        boolean isReverseDirection = course >= 150 && course <= 330;
        int nearestPointIndex = findNearestPointIndex(currentLatitude, currentLongitude, isReverseDirection);

        // 确保索引有效
        if (nearestPointIndex < 0 || nearestPointIndex + (isReverseDirection ? 1 : -1) < 0 || nearestPointIndex + (isReverseDirection ? 1 : -1) >= STANDARD_POINTS.length) {
            return null;
        }

        // 获取当前点和下一个标准点
        double[] currentPoint = STANDARD_POINTS[nearestPointIndex];
        double[] nextPoint = STANDARD_POINTS[nearestPointIndex + (isReverseDirection ? 1 : -1)];

        // 计算方向向量（单位化）
        double[] directionVector = calculateUnitDirectionVector(currentPoint, nextPoint);

        // 计算新的经纬度
        double distanceTraveledInMeters = speedInKnots * 0.514444; // 将速度从节转换为米/秒
        double newLatitude = currentLatitude + (distanceTraveledInMeters * directionVector[0]) / METERS_PER_DEGREE_LATITUDE;
        double newLongitude = currentLongitude + (distanceTraveledInMeters * directionVector[1]) / (METERS_PER_DEGREE_LATITUDE * Math.cos(Math.toRadians(currentLatitude)));

        return new double[]{newLatitude, newLongitude};
    }

    /**
     * 计算从点A到点B的方向向量（单位化）。
     */
    private static double[] calculateUnitDirectionVector(double[] startPoint, double[] endPoint) {
        double latitudeDifferenceInMeters = (endPoint[0] - startPoint[0]) * METERS_PER_DEGREE_LATITUDE;
        double longitudeDifferenceInMeters = (endPoint[1] - startPoint[1]) * METERS_PER_DEGREE_LATITUDE * Math.cos(Math.toRadians(startPoint[0]));

        double vectorMagnitude = Math.sqrt(latitudeDifferenceInMeters * latitudeDifferenceInMeters + longitudeDifferenceInMeters * longitudeDifferenceInMeters);
        return new double[]{latitudeDifferenceInMeters / vectorMagnitude, longitudeDifferenceInMeters / vectorMagnitude};
    }

    /**
     * 获取最近的标准点索引。
     */
    public static int findNearestPointIndex(double currentLatitude, double currentLongitude, boolean isReverseDirection) {
        int closestPointIndex = -1;
        double minimumDistance = Double.MAX_VALUE;
        double latitudeToMetersFactor = METERS_PER_DEGREE_LATITUDE;
        double longitudeToMetersFactor = METERS_PER_DEGREE_LATITUDE * Math.cos(Math.toRadians(currentLatitude));

        // 根据遍历方向进行循环
        int startIndex = isReverseDirection ? 0 : STANDARD_POINTS.length - 1;
        int endIndex = isReverseDirection ? STANDARD_POINTS.length : -1;
        int step = isReverseDirection ? 1 : -1;

        for (int i = startIndex; i != endIndex; i += step) {
            double[] standardPoint = STANDARD_POINTS[i];
            double latitudeDifferenceInMeters = (currentLatitude - standardPoint[0]) * latitudeToMetersFactor;
            double longitudeDifferenceInMeters = (currentLongitude - standardPoint[1]) * longitudeToMetersFactor;
            double distanceToCurrentPoint = Math.sqrt(latitudeDifferenceInMeters * latitudeDifferenceInMeters + longitudeDifferenceInMeters * longitudeDifferenceInMeters);

            if (distanceToCurrentPoint < minimumDistance) {
                minimumDistance = distanceToCurrentPoint;
                closestPointIndex = i;
            }
        }
        return closestPointIndex;
    }
}
